home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / jp4dpmi.zip / JDMAIN.C < prev    next >
C/C++ Source or Header  |  1992-12-14  |  14KB  |  516 lines

  1. /*
  2.  * jdmain.c
  3.  *
  4.  * Copyright (C) 1991, 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains an MS-DOS user interface for the JPEG decompressor.
  9.  * It follows DOS practice more closely than does the standard jdmain.c.
  10.  * This compiles under Borland C or Microsoft C; don't know about others.
  11.  * If you are using jmemnobs.c, #define FREE_MEM_ESTIMATE=0.
  12.  */
  13.  
  14. #include "jinclude.h"
  15. #include <stdlib.h>        /* to declare exit() */
  16. #include <string.h>        /* string functions */
  17. #include <signal.h>        /* to declare signal() */
  18.  
  19. #ifdef __TURBOC__
  20.                 /* Borland C declarations */
  21. #include <dir.h>        /* for findfirst/findnext */
  22. typedef struct ffblk FF_DATA;
  23. #define FF_NAME  ff_name
  24. #define FINDFIRST(path,blk)    findfirst(path, blk, 0)
  25. #define FINDNEXT(blk)        findnext(blk)
  26.  
  27. #include <alloc.h>        /* for farcoreleft() */
  28. /* In Borland C, force -m equal to 95% of farcoreleft figure */
  29. #define FREE_MEM_ESTIMATE  ((farcoreleft() * 95L) / 100L)
  30.  
  31. #else /* !__TURBOC__ */
  32.                 /* Microsoft C declarations */
  33. #include <dos.h>        /* for findfirst/findnext */
  34. typedef struct find_t FF_DATA;
  35. #define FF_NAME  name
  36. #define FINDFIRST(path,blk)    _dos_findfirst(path, _A_NORMAL, blk)
  37. #define FINDNEXT(blk)        _dos_findnext(blk)
  38.  
  39. #endif /* __TURBOC__ */
  40.  
  41. #define READ_BINARY    "rb"
  42. #define WRITE_BINARY    "wb"
  43.  
  44. #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
  45. #define EXIT_FAILURE  1
  46. #endif
  47. #ifndef EXIT_SUCCESS
  48. #define EXIT_SUCCESS  0
  49. #endif
  50.  
  51.  
  52. #include "jversion.h"        /* for version message */
  53.  
  54.  
  55. /*
  56.  * PD version of getopt(3).
  57.  */
  58.  
  59. #include "egetopt.c"
  60.  
  61.  
  62. /*
  63.  * This list defines the known output image formats
  64.  * (not all of which need be supported by a given version).
  65.  * You can change the default output format by defining DEFAULT_FMT;
  66.  * indeed, you had better do so if you undefine GIF_SUPPORTED.
  67.  */
  68.  
  69. typedef enum {
  70.     FMT_GIF,        /* GIF format */
  71.     FMT_PPM,        /* PPM/PGM (PBMPLUS formats) */
  72.     FMT_RLE,        /* RLE format */
  73.     FMT_TARGA,        /* Targa format */
  74.     FMT_TIFF        /* TIFF format */
  75. } IMAGE_FORMATS;
  76.  
  77. #ifndef DEFAULT_FMT        /* so can override from CFLAGS in Makefile */
  78. #define DEFAULT_FMT    FMT_GIF
  79. #endif
  80.  
  81. static IMAGE_FORMATS requested_fmt;
  82.  
  83.  
  84. /*
  85.  * This routine gets control after the input file header has been read.
  86.  * It must determine what output file format is to be written,
  87.  * and make any other decompression parameter changes that are desirable.
  88.  */
  89.  
  90. METHODDEF void
  91. d_ui_method_selection (decompress_info_ptr cinfo)
  92. {
  93.   /* if grayscale or CMYK input, force similar output; */
  94.   /* else leave the output colorspace as set by options. */
  95.   if (cinfo->jpeg_color_space == CS_GRAYSCALE)
  96.     cinfo->out_color_space = CS_GRAYSCALE;
  97.   else if (cinfo->jpeg_color_space == CS_CMYK)
  98.     cinfo->out_color_space = CS_CMYK;
  99.  
  100.   /* select output file format */
  101.   /* Note: jselwxxx routine may make additional parameter changes,
  102.    * such as forcing color quantization if it's a colormapped format.
  103.    */
  104.   switch (requested_fmt) {
  105. #ifdef GIF_SUPPORTED
  106.   case FMT_GIF:
  107.     jselwgif(cinfo);
  108.     break;
  109. #endif
  110. #ifdef PPM_SUPPORTED
  111.   case FMT_PPM:
  112.     jselwppm(cinfo);
  113.     break;
  114. #endif
  115. #ifdef RLE_SUPPORTED
  116.   case FMT_RLE:
  117.     jselwrle(cinfo);
  118.     break;
  119. #endif
  120. #ifdef TARGA_SUPPORTED
  121.   case FMT_TARGA:
  122.     jselwtarga(cinfo);
  123.     break;
  124. #endif
  125.   default:
  126.     ERREXIT(cinfo->emethods, "Unsupported output file format");
  127.     break;
  128.   }
  129. }
  130.  
  131.  
  132. /*
  133.  * Signal catcher to ensure that temporary files are removed before aborting.
  134.  * Doesn't do anything during intervals where emethods is NULL.
  135.  */
  136.  
  137. static external_methods_ptr emethods; /* for access to free_all */
  138.  
  139. LOCAL void
  140. signal_catcher (int signum)
  141. {
  142.   if (emethods != NULL) {
  143.     emethods->trace_level = 0;    /* turn off trace output */
  144.     (*emethods->free_all) ();    /* clean up memory allocation & temp files */
  145.   }
  146.   exit(EXIT_FAILURE);
  147. }
  148.  
  149.  
  150. LOCAL void
  151. usage (void)
  152. /* complain about bad command line */
  153. {
  154.   fprintf(stderr, "Usage: djpeg [switches] inputfile(s)\n");
  155.   fprintf(stderr, "List of input files may use wildcards (* and ?)\n");
  156.   fprintf(stderr, "If input file name has no extension, .JPG is assumed\n");
  157.   fprintf(stderr, "Output filename is same as input filename, except for extension\n");
  158.   fprintf(stderr, "Optional switches:\n");
  159. #ifdef GIF_SUPPORTED
  160.   fprintf(stderr, "  -G          Select GIF output, extension .GIF  (default)\n");
  161. #endif
  162. #ifdef PPM_SUPPORTED
  163.   fprintf(stderr, "  -P          Select PPM/PGM output, extension .PPM\n");
  164. #endif
  165. #ifdef RLE_SUPPORTED
  166.   fprintf(stderr, "  -R          Select Utah RLE output, extension .RLE\n");
  167. #endif
  168. #ifdef TARGA_SUPPORTED
  169.   fprintf(stderr, "  -T          Select Targa output, extension .TGA\n");
  170. #endif
  171.   fprintf(stderr, "  -g          Force grayscale output\n");
  172.   fprintf(stderr, "  -q colors   Quantize to no more than N colors\n");
  173.   fprintf(stderr, "  -1          Use 1-pass quantization (fast, low quality)\n");
  174.   fprintf(stderr, "  -D          Don't use dithering in quantization\n");
  175.   fprintf(stderr, "  -b          Apply cross-block smoothing\n");
  176. #ifndef FREE_MEM_ESTIMATE
  177.   fprintf(stderr, "  -m memory   Maximum memory to use (default 300K); see USAGE\n");
  178. #endif
  179.   fprintf(stderr, "  -d          Generate debug output\n");
  180.   exit(EXIT_FAILURE);
  181. }
  182.  
  183.  
  184. /* Display progress report */
  185.  
  186. METHODDEF void
  187. progress_monitor (decompress_info_ptr cinfo, long loopcounter, long looplimit)
  188. {
  189.   if (cinfo->total_passes > 1) {
  190.     fprintf(stderr, "\rPass %d/%d: %3d%% ",
  191.         cinfo->completed_passes+1, cinfo->total_passes,
  192.         (int) (loopcounter*100L/looplimit));
  193.   } else {
  194.     fprintf(stderr, "\r %3d%% ",
  195.         (int) (loopcounter*100L/looplimit));
  196.   }
  197.   fflush(stderr);
  198. }
  199.  
  200.  
  201. /*
  202.  * Check for overwrite of an existing file; clear it with user
  203.  */
  204.  
  205. LOCAL boolean
  206. is_write_ok (char * outfilename)
  207. {
  208.   FILE * ofile;
  209.   int ch;
  210.  
  211.   ofile = fopen(outfilename, READ_BINARY);
  212.   if (ofile == NULL)
  213.     return TRUE;        /* not present */
  214.   fclose(ofile);        /* oops, it is present */
  215.  
  216.   for (;;) {
  217.     fprintf(stderr, "%s already exists, overwrite it? [y/n] ",
  218.         outfilename);
  219.     fflush(stderr);
  220.     ch = getc(stdin);
  221.     fflush(stdin);        /* flush rest of line */
  222.     switch (ch) {
  223.     case 'Y':
  224.     case 'y':
  225.       return TRUE;
  226.     case 'N':
  227.     case 'n':
  228.       return FALSE;
  229.     /* otherwise, ask again */
  230.     }
  231.   }
  232. }
  233.  
  234.  
  235. /*
  236.  * Save current switch values here --- necessary for multiple input files!
  237.  */
  238.  
  239. static boolean b_smooth;    /* -b */
  240. static boolean gray_scale;    /* -g */
  241. static int num_colors;        /* -q, or 0 if not seen */
  242. static boolean two_pass_q;    /* not -1 */
  243. static boolean do_dither;    /* not -D */
  244. static long cur_mem;        /* -m, or value of FREE_MEM_ESTIMATE */
  245. static int cur_trace;        /* -d */
  246.  
  247. #define MAX_FNAME_LEN 150
  248.  
  249.  
  250. /*
  251.  * Process a single input file
  252.  */
  253.  
  254. LOCAL void
  255. process_one_file (char * infilename)
  256. {
  257.   struct Decompress_info_struct cinfo;
  258.   struct Decompress_methods_struct dc_methods;
  259.   struct External_methods_struct e_methods;
  260.   char outfilename[MAX_FNAME_LEN];
  261.   int i;
  262.  
  263.   /* Select the input and output files */
  264.  
  265.   if ((cinfo.input_file = fopen(infilename, READ_BINARY)) == NULL) {
  266.     fprintf(stderr, "djpeg: can't open %s\n", infilename);
  267.     return;
  268.   }
  269.   /* Make outfilename be infilename with appropriate extension */
  270.   strcpy(outfilename, infilename);
  271.   for (i = strlen(outfilename)-1; i >= 0; i--) {
  272.     switch (outfilename[i]) {
  273.     case ':':
  274.     case '/':
  275.     case '\\':
  276.       i = 0;            /* stop scanning */
  277.       break;
  278.     case '.':
  279.       outfilename[i] = '\0';    /* lop off existing extension */
  280.       i = 0;            /* stop scanning */
  281.       break;
  282.     default:
  283.       break;            /* keep scanning */
  284.     }
  285.   }
  286.   switch (requested_fmt) {
  287.   case FMT_GIF:
  288.     strcat(outfilename, ".GIF");
  289.     break;
  290.   case FMT_PPM:
  291.     strcat(outfilename, ".PPM");
  292.     break;
  293.   case FMT_RLE:
  294.     strcat(outfilename, ".RLE");
  295.     break;
  296.   case FMT_TARGA:
  297.     strcat(outfilename, ".TGA");
  298.     break;
  299.   }
  300.  
  301.   if (! is_write_ok(outfilename)) {
  302.     fclose(cinfo.input_file);
  303.     return;
  304.   }
  305.   if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
  306.     fprintf(stderr, "djpeg: can't create %s\n", outfilename);
  307.     fclose(cinfo.input_file);
  308.     return;
  309.   }
  310.  
  311.   /* Initialize the system-dependent method pointers. */
  312.   cinfo.methods = &dc_methods;
  313.   cinfo.emethods = &e_methods;
  314.   jselerror(&e_methods);    /* error/trace message routines */
  315.   jselmemmgr(&e_methods);    /* memory allocation routines */
  316.   dc_methods.d_ui_method_selection = d_ui_method_selection;
  317.  
  318.   /* Now OK to enable signal catcher. */
  319.   emethods = &e_methods;
  320.  
  321.   /* Set up JPEG parameters. */
  322.   j_d_defaults(&cinfo, TRUE);
  323.   cinfo.do_block_smoothing = b_smooth;
  324.   if (gray_scale)
  325.     cinfo.out_color_space = CS_GRAYSCALE;
  326.   if (num_colors > 0) {
  327.     cinfo.desired_number_of_colors = num_colors;
  328.     cinfo.quantize_colors = TRUE;
  329.   }
  330.   cinfo.two_pass_quantize = two_pass_q;
  331.   cinfo.use_dithering = do_dither;
  332.   e_methods.max_memory_to_use = cur_mem;
  333.   e_methods.trace_level = cur_trace;
  334.  
  335.   /* Start up progress display, unless trace output is on */
  336.   fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename);
  337.   if (cur_trace == 0)
  338.     dc_methods.progress_monitor = progress_monitor;
  339.   
  340.   /* Set up to read a JFIF or baseline-JPEG file. */
  341.   /* A smarter UI would inspect the first few bytes of the input file */
  342.   /* to determine its type. */
  343. #ifdef JFIF_SUPPORTED
  344.   jselrjfif(&cinfo);
  345. #else
  346.   You shoulda defined JFIF_SUPPORTED.   /* deliberate syntax error */
  347. #endif
  348.  
  349.   /* Do it to it! */
  350.   jpeg_decompress(&cinfo);
  351.  
  352.   /* Clear away progress display */
  353.   if (cur_trace == 0)
  354.     fprintf(stderr, "\r                \r");
  355.   fflush(stderr);
  356.  
  357.   /* All done. Close files, disable signal catcher */
  358.   fclose(cinfo.input_file);
  359.   fclose(cinfo.output_file);
  360.   emethods = NULL;
  361. }
  362.  
  363.  
  364. /*
  365.  * Process one filespec; expand wildcards
  366.  */
  367.  
  368. LOCAL void
  369. process_filespec (char * filespec)
  370. {
  371.   FF_DATA ffblock;
  372.   char infilename[MAX_FNAME_LEN];
  373.   int pathlen, i;
  374.   boolean hasext;
  375.  
  376.   /* Determine whether there is a path and an extension */
  377.   pathlen = 0;
  378.   hasext = FALSE;
  379.   for (i = strlen(filespec)-1; i >= 0; i--) {
  380.     switch (filespec[i]) {
  381.     case ':':
  382.     case '/':
  383.     case '\\':
  384.       pathlen = i+1;        /* path part ends here */
  385.       i = 0;            /* stop scanning */
  386.       break;
  387.     case '.':
  388.       hasext = TRUE;        /* there is an extension */
  389.       break;
  390.     default:
  391.       break;            /* keep scanning */
  392.     }
  393.   }
  394.  
  395.   /* Make infilename be filespec; if no explicit extension, attach .JPG */
  396.   strcpy(infilename, filespec);
  397.   if (! hasext)
  398.     strcat(infilename, ".JPG");
  399.  
  400.   /* Scan over matching files */
  401.   if (FINDFIRST(infilename, &ffblock) != 0) {
  402.     fprintf(stderr, "No files matching %s\n", infilename);
  403.   } else {
  404.     do {
  405.       strcpy(infilename, filespec);
  406.       strcpy(infilename + pathlen, ffblock.FF_NAME);
  407.       process_one_file(infilename);
  408.     } while (FINDNEXT(&ffblock) == 0);
  409.   }
  410. }
  411.  
  412.  
  413. /*
  414.  * The main program.
  415.  */
  416.  
  417. GLOBAL int
  418. main (int argc, char **argv)
  419. {
  420.   int c;
  421.  
  422.   /* Set up signal catcher. */
  423.   emethods = NULL;
  424.   signal(SIGINT, signal_catcher);
  425. #ifdef SIGTERM            /* not all systems have SIGTERM */
  426.   signal(SIGTERM, signal_catcher);
  427. #endif
  428.  
  429.   /* Scan command line, process switches */
  430.  
  431.   requested_fmt = DEFAULT_FMT;    /* initialize default switch values */
  432.   b_smooth = FALSE;
  433.   gray_scale = FALSE;
  434.   num_colors = 0;
  435.   two_pass_q = TRUE;
  436.   do_dither = TRUE;
  437. #ifdef FREE_MEM_ESTIMATE
  438.   cur_mem = FREE_MEM_ESTIMATE;
  439. #else
  440.   cur_mem = 300000L;        /* reasonable default for DOS */
  441. #endif
  442.   cur_trace = 0;
  443.   
  444.   while ((c = egetopt(argc, argv, "GPRTbgq:1Dm:d")) != EOF)
  445.     switch (c) {
  446.     case 'G':            /* GIF output format. */
  447.       requested_fmt = FMT_GIF;
  448.       break;
  449.     case 'P':            /* PPM output format. */
  450.       requested_fmt = FMT_PPM;
  451.       break;
  452.     case 'R':            /* RLE output format. */
  453.       requested_fmt = FMT_RLE;
  454.       break;
  455.     case 'T':            /* Targa output format. */
  456.       requested_fmt = FMT_TARGA;
  457.       break;
  458.     case 'b':            /* Enable cross-block smoothing. */
  459.       b_smooth = TRUE;
  460.       break;
  461.     case 'g':            /* Force grayscale output. */
  462.       gray_scale = TRUE;
  463.       break;
  464.     case 'q':            /* Do color quantization. */
  465.       if (optarg == NULL)
  466.     usage();
  467.       if (sscanf(optarg, "%d", &num_colors) != 1)
  468.     usage();
  469.       break;
  470.     case '1':            /* Use fast one-pass quantization. */
  471.       two_pass_q = FALSE;
  472.       break;
  473.     case 'D':            /* Suppress dithering in color quantization. */
  474.       do_dither = FALSE;
  475.       break;
  476.     case 'm':            /* Maximum memory in Kb (or Mb with 'm'). */
  477.       { long lval;
  478.     char ch = 'x';
  479.  
  480.     if (optarg == NULL)
  481.       usage();
  482.     if (sscanf(optarg, "%ld%c", &lval, &ch) < 1)
  483.       usage();
  484.     if (ch == 'm' || ch == 'M')
  485.       lval *= 1000L;
  486.     cur_mem = lval * 1000L;
  487.       }
  488.       break;
  489.     case 'd':            /* Debugging. */
  490.       /* On first -d, print version identification */
  491.       if (cur_trace == 0)
  492.     fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
  493.         JVERSION, JCOPYRIGHT);
  494.       cur_trace++;
  495.       break;
  496.     case '?':
  497.     default:
  498.       usage();
  499.       break;
  500.     }
  501.  
  502.   /* Process file specifications */
  503.   if (optind >= argc)
  504.     usage();            /* no filespecs?? */
  505.  
  506.   while (optind < argc)
  507.     process_filespec(argv[optind++]);
  508.  
  509.   /* All done. */
  510.   exit(EXIT_SUCCESS);
  511.   return 0;            /* suppress no-return-value warnings */
  512. }
  513.  
  514. void
  515. txtmode(){}
  516.